package main

import (
	"encoding/xml"
	"github.com/360EntSecGroup-Skylar/excelize/v2"
	"io/ioutil"
	"log"
	"os"
	"sort"
	"strings"
)

func main() {
	modulePath := map[string]string{
		"app":           "E:\\AndroidStudioProjects\\70mai_Sport\\maiwatch\\app\\src\\main\\res",
		"common-health": "E:\\AndroidStudioProjects\\70mai_Sport\\common-libs\\common-health\\src\\main\\res",
		"common-util":   "E:\\AndroidStudioProjects\\70mai_Sport\\common-libs\\common-util\\src\\main\\res",
		"common-base":   "E:\\AndroidStudioProjects\\70mai_Sport\\maiwatch\\common-base\\src\\main\\res",
	}

	excelFile, err := excelize.OpenFile("HealthAndroid.xlsx")
	if err != nil {
		log.Fatal(err)
	}
	keyName := []string{
		"module", "key", "zh-rCN", "default", "ru", "ja", "es",
		"zh-rTW", "de", "it", "fr", "pt", "in", "pl", "th",
	}
	for _, sheetName := range excelFile.GetSheetList() {
		rows, err := excelFile.GetRows(sheetName)
		if err != nil {
			log.Fatal(err)
		}
		modules := make([]string, 0)
		translates := make([]Translate, 0)
		for i, row := range rows {
			if i == 0 {
				continue
			}
			translate := Translate{}
			translate.Translation = make(map[string]string)
			for i, cell := range row {
				if i == 0 {
					translate.Module = cell

					var contains = false
					for _, module := range modules {
						if module == cell {
							contains = true
							break
						}
					}
					if !contains {
						modules = append(modules, cell)
					}
				} else if i == 1 {
					translate.Key = cell
				} else {
					translate.Translation[keyName[i]] = cell
				}
			}
			translates = append(translates, translate)
		}

		for _, module := range []string{"app", "common-health", "common-util", "common-base"} {
			mkdir(module)
			for _, lang := range []string{"zh-rCN", "default", "ru", "ja", "es", "zh-rTW", "de", "it", "fr", "pt", "in", "pl", "th"} {
				var valueAppend string
				if lang != "default" {
					valueAppend = "-" + lang
				}
				dir := modulePath[module] + "\\values" + valueAppend
				_ = os.MkdirAll(dir, os.ModePerm)

				var resourcesImpl ResourcesImpl
				var outputPath string
				if sheetName == "strings" {
					continue
					outputPath = dir + "\\strings.xml"
					log.Print(outputPath)
					_, err := os.Stat(outputPath)
					resources := Resources{}
					resources.XMLName = "resources"
					resources.Xliff = "urn:oasis:names:tc:xliff:document:1.2"
					if os.IsNotExist(err) {
						for _, translate := range translates {
							if translate.Module != module {
								continue
							}
							if translate.Translation[lang] == "" {
								continue
							}
							resources.Strings = append(resources.Strings, Strings{
								XMLName: "strings", Name: translate.Key, Data: translate.Translation[lang],
							})
						}

					} else if err == nil {
						all, err := ioutil.ReadFile(outputPath)
						if err != nil {
							log.Fatal(err)
						}
						err = xml.Unmarshal(all, &resources)
						if err != nil {
							log.Fatal(err)
						}
						for _, translate := range translates {
							if translate.Module != module {
								continue
							}
							if translate.Translation[lang] == "" {
								continue
							}
							var contains = false
							for i, resStr := range resources.Strings {
								if resStr.Name == translate.Key {
									contains = true
									resources.Strings[i].Data = translate.Translation[lang]
									break
								}
							}
							if !contains {
								resources.Strings = append(resources.Strings,
									Strings{XMLName: "strings", Name: translate.Key, Data: translate.Translation[lang]})
							}
						}
					}

					sort.Slice(resources.Strings, func(i, j int) bool {
						return strings.Compare(resources.Strings[i].Name, resources.Strings[j].Name) < 0
					})
					resourcesImpl = &resources
				} else if sheetName == "arrays" {
					outputPath = dir + "\\arrays.xml"
					log.Print(outputPath)
					_, err := os.Stat(outputPath)
					resources := ArrayResources{}
					resources.XMLName = "resources"
					resources.Xliff = "urn:oasis:names:tc:xliff:document:1.2"
					if os.IsNotExist(err) {
						for _, translate := range translates {
							if translate.Module != module {
								continue
							}
							if translate.Translation[lang] == "" {
								continue
							}
							items := make([]ArrayItem, 0)
							splits := strings.Split(translate.Translation[lang], ", ")
							if len(splits) != 0 {
								for _, split := range splits {
									items = append(items, ArrayItem{
										XMLName: "item",
										Data:    split,
									})
								}
								resources.Array = append(resources.Array, Array{
									XMLName: "string-array", Name: translate.Key, Item: items,
								})
							}
						}
					} else if err == nil {
						all, err := ioutil.ReadFile(outputPath)
						if err != nil {
							log.Fatal(err)
						}
						err = xml.Unmarshal(all, &resources)
						if err != nil {
							log.Fatal(err)
						}
						for _, translate := range translates {
							if translate.Module != module {
								continue
							}
							if translate.Translation[lang] == "" {
								continue
							}
							var contains = false
							for i, resStr := range resources.Array {
								if translate.Module != module {
									continue
								}
								if translate.Translation[lang] == "" {
									continue
								}
								if resStr.Name == translate.Key {
									contains = true
									splits := strings.Split(translate.Translation[lang], ", ")
									for _, split := range splits {
										resources.Array[i].Item = append(resources.Array[i].Item, ArrayItem{
											XMLName: "item",
											Data:    split,
										})
									}
									break
								}
							}
							if !contains {
								items := make([]ArrayItem, 0)
								splits := strings.Split(translate.Translation[lang], ", ")
								if len(splits) != 0 {
									for _, split := range splits {
										items = append(items, ArrayItem{
											XMLName: "item",
											Data:    split,
										})
									}
									resources.Array = append(resources.Array, Array{
										XMLName: "string-array", Name: translate.Key, Item: items,
									})
								}
							}
						}
					}
					sort.Slice(resources.Array, func(i, j int) bool {
						return strings.Compare(resources.Array[i].Name, resources.Array[j].Name) < 0
					})
					resourcesImpl = &resources
				} else if sheetName == "plurals" {
					outputPath = dir + "\\plurals.xml"
					log.Print(outputPath)
					_, err := os.Stat(outputPath)
					resources := PluralsResources{}
					resources.XMLName = "resources"
					resources.Xliff = "urn:oasis:names:tc:xliff:document:1.2"
					if os.IsNotExist(err) {
						for _, translate := range translates {
							if translate.Module != module {
								continue
							}
							if translate.Translation[lang] == "" {
								continue
							}
							items := formatPlurals(translate.Translation[lang])
							if len(items) != 0 {
								resources.Plurals = append(resources.Plurals, Plurals{
									XMLName: "plurals", Name: translate.Key, Item: items,
								})
							}
						}
					} else if err == nil {
						all, err := ioutil.ReadFile(outputPath)
						if err != nil {
							log.Fatal(err)
						}
						err = xml.Unmarshal(all, &resources)
						if err != nil {
							log.Fatal(err)
						}
						for _, translate := range translates {
							if translate.Module != module {
								continue
							}
							if translate.Translation[lang] == "" {
								continue
							}

							var contains = false
							formatValue := formatPlurals(translate.Translation[lang])
							for i, resStr := range resources.Plurals {
								if resStr.Name == translate.Key {
									contains = true
									resources.Plurals[i].Item = formatValue
									break
								}
							}
							if !contains {
								if len(formatValue) != 0 {
									resources.Plurals = append(resources.Plurals, Plurals{
										XMLName: "plurals", Name: translate.Key, Item: formatValue,
									})
								}
							}
						}
					}
					sort.Slice(resources.Plurals, func(i, j int) bool {
						return strings.Compare(resources.Plurals[i].Name, resources.Plurals[j].Name) < 0
					})
					resourcesImpl = &resources
				}
				if resourcesImpl != nil && resourcesImpl.ItemCount() != 0 {
					_ = os.Remove(outputPath)
					create, err := os.Create(outputPath)
					if err != nil {
						log.Fatal(err)
					}
					_, err = create.Write([]byte("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"))
					if err != nil {
						log.Fatal(err)
					}
					marshal, err := xml.MarshalIndent(resourcesImpl, "", "\t")
					if err != nil {
						log.Fatal(err)
					}
					_, err = create.Write(marshal)
					if err != nil {
						log.Fatal(err)
					}
					err = create.Close()
					if err != nil {
						log.Fatal(err)
					}
				}
			}
		}
	}
}

func formatPlurals(translate string) []PluralsItem {
	split := strings.Split(translate, ", ")
	items := make([]PluralsItem, 0)
	if len(split) == 2 {
		items = append(items, PluralsItem{
			Quantity: "one",
			Data:     split[0],
		})
		items = append(items, PluralsItem{
			Quantity: "other",
			Data:     split[1],
		})
	} else if len(split) == 4 {
		items = append(items, PluralsItem{
			Quantity: "one",
			Data:     split[0],
		})
		items = append(items, PluralsItem{
			Quantity: "few",
			Data:     split[1],
		})
		items = append(items, PluralsItem{
			Quantity: "many",
			Data:     split[2],
		})
		items = append(items, PluralsItem{
			Quantity: "other",
			Data:     split[3],
		})
	} else if len(split) == 1 {
		items = append(items, PluralsItem{
			Quantity: "other",
			Data:     split[0],
		})
	}
	return items
}

func mkdir(module string) {
	_, err := os.Stat("./" + module)
	if os.IsNotExist(err) {
		err = os.Mkdir("./"+module, os.ModePerm)
		if err != nil {
			log.Fatal(err)
		}
	} else if err != nil {
		log.Fatal(err)
	}
}

type ResourcesImpl interface {
	ItemCount() int
}

type Resources struct {
	XMLName string    `xml:"resources"`
	Xliff   string    `xml:"xmlns:xliff,attr"`
	Strings []Strings `xml:"string"`
}

func (r *Resources) ItemCount() int {
	return len(r.Strings)
}

type Strings struct {
	XMLName string `xml:"string"`
	Name    string `xml:"name,attr"`
	Data    string `xml:",chardata"`
}

type PluralsResources struct {
	XMLName string    `xml:"resources"`
	Xliff   string    `xml:"xmlns:xliff,attr"`
	Plurals []Plurals `xml:"plurals"`
}

func (r *PluralsResources) ItemCount() int {
	return len(r.Plurals)
}

type Plurals struct {
	XMLName string        `xml:"plurals"`
	Name    string        `xml:"name,attr"`
	Item    []PluralsItem `xml:"item"`
}

type PluralsItem struct {
	XMLName  string `xml:"item"`
	Quantity string `xml:"quantity,attr"`
	Data     string `xml:",chardata"`
}

func (r *ArrayResources) ItemCount() int {
	return len(r.Array)
}

type ArrayResources struct {
	XMLName string  `xml:"resources"`
	Xliff   string  `xml:"xmlns:xliff,attr"`
	Array   []Array `xml:"string-array"`
}

type Array struct {
	XMLName string      `xml:"string-array"`
	Name    string      `xml:"name,attr"`
	Item    []ArrayItem `xml:"item"`
}

type ArrayItem struct {
	XMLName string `xml:"item"`
	Data    string `xml:",chardata"`
}

type Translate struct {
	Module      string
	Key         string
	Translation map[string]string
}
